﻿using System;
using System.Collections.Generic;
using System.Linq;
using Autodesk.Revit.DB;
using YArchitech.Revit;
using YJKRevitKernel.ElementSearchUtility.LinkDocumentSuite;
using YJKRevitKernel.XYZUtility;
using YJKGeometryFuncs;
using YJKPresentation.Utils;

namespace YJKRevitDimensionText.OneKeyPlanDim.DimesionDataEx
{
	internal class GridConstructor
	{
		public GridConstructor(Autodesk.Revit.DB.Document doc)
		{
			this.m_doc = doc;
			this.FilterGrid();
		}

		public List<Grid> GetAllGrid()
		{
			return this.m_lstAllGrid;
		}

		public List<GridGroupDataEx> GetGridGroup()
		{
			this.Group();
			return this.m_lstGridGroup;
		}

		public List<GridGroupDataEx> GetAllParallelGrid()
		{
			try
			{
				foreach (KeyValuePair<int, List<BaseLinkDocumentResultBean>> keyValuePair in this.m_dicLinkInsIdAndGrid)
				{
					List<BaseLinkDocumentResultBean> value = keyValuePair.Value;
					if (!EnumerableExternsion.IsEmpty<BaseLinkDocumentResultBean>(value))
					{
						Transform trans = value.FirstOrDefault<BaseLinkDocumentResultBean>().GetTotalTransform();
						List<GridInfoCache> source = value.ConvertAll<GridInfoCache>((BaseLinkDocumentResultBean thisItem) => new GridInfoCache(thisItem.UseElement as Grid, this.m_doc, trans));
						Dictionary<string, List<GridInfoCache>> dicNameGrid = (from thisItem in source
						where thisItem.IsStartBubbleVisible || thisItem.IsEndBubbleVisible
						group thisItem by thisItem.ThisGrid.Name).ToDictionary((IGrouping<string, GridInfoCache> funKey) => funKey.Key, (IGrouping<string, GridInfoCache> funValue) => funValue.ToList<GridInfoCache>());
						IEnumerable<IGrouping<XYZ, GridInfoCache>> groupDirAndGrid = (from thisItem in source
						where dicNameGrid.ContainsKey(thisItem.ThisGrid.Name)
						select thisItem).ToList<GridInfoCache>().GroupBy((GridInfoCache thisItem) => thisItem.ThisGridLine.Direction, new XYZComparer(0.0001));
						foreach (KeyValuePair<XYZ, List<GridInfoCache>> keyValuePair2 in this.OrderParallelGrid(groupDirAndGrid))
						{
							GridGroupDataEx item = new GridGroupDataEx(keyValuePair2.Key, keyValuePair2.Value);
							this.m_lstParallelGridGroup.Add(item);
						}
					}
				}
			}
			catch (Exception)
			{
			}
			return this.m_lstParallelGridGroup;
		}

		private void FilterGrid()
		{
			try
			{
				IEnumerable<BaseLinkDocumentResultBean> source = new FilteredElementCollectorLinkDocument(this.m_doc).OfCalss(typeof(Grid)).ToBeans().Where(delegate(BaseLinkDocumentResultBean thisItem)
				{
					bool result;
					try
					{
						Grid grid = thisItem.UseElement as Grid;
						if (!grid.CanBeVisibleInView(this.m_doc.ActiveView) || grid.IsCurved || grid.IsHidden(this.m_doc.ActiveView))
						{
							result = false;
						}
						else
						{
							result = true;
						}
					}
					catch (Exception)
					{
						result = false;
					}
					return result;
				});
				this.m_lstAllGrid = (from thisItem in source
				select thisItem.UseElement as Grid).ToList<Grid>();
				this.m_dicLinkInsIdAndGrid = (from thisItem in source
				group thisItem by thisItem.LinkeInstanceId).ToDictionary((IGrouping<int, BaseLinkDocumentResultBean> Key) => Key.Key, (IGrouping<int, BaseLinkDocumentResultBean> Value) => Value.ToList<BaseLinkDocumentResultBean>());
			}
			catch (Exception)
			{
			}
		}

		private void Group()
		{
			try
			{
				this.m_lstGridGroup = new List<GridGroupDataEx>();
				foreach (KeyValuePair<int, List<BaseLinkDocumentResultBean>> keyValuePair in this.m_dicLinkInsIdAndGrid)
				{
					List<BaseLinkDocumentResultBean> value = keyValuePair.Value;
					if (!EnumerableExternsion.IsEmpty<BaseLinkDocumentResultBean>(value))
					{
						Transform trans = value.FirstOrDefault<BaseLinkDocumentResultBean>().GetTotalTransform();
						IEnumerable<IGrouping<XYZ, GridInfoCache>> groupDirAndGrid = value.ConvertAll<GridInfoCache>((BaseLinkDocumentResultBean thisItem) => new GridInfoCache(thisItem.UseElement as Grid, this.m_doc, trans)).GroupBy((GridInfoCache thisItem) => thisItem.ThisGridLine.Direction, new XYZComparer(0.0001));
						Dictionary<XYZ, List<GridInfoCache>> dictionary = this.OrderParallelGrid(groupDirAndGrid);
						List<OneGroupGridData> list = new List<OneGroupGridData>();
						foreach (KeyValuePair<XYZ, List<GridInfoCache>> keyValuePair2 in dictionary)
						{
							XYZ key = keyValuePair2.Key;
							List<GridInfoCache> value2 = keyValuePair2.Value;
							List<OneGroupGridData> collection = this.GroupByBubble(value2, key);
							list.AddRange(collection);
						}
						foreach (OneGroupGridData oneGroupGridData in list)
						{
							if (!EnumerableExternsion.IsEmpty<GridInfoCache>(oneGroupGridData.GridInfoCaches) && oneGroupGridData.GridInfoCaches.Count >= 2)
							{
								GridGroupDataEx item = new GridGroupDataEx(oneGroupGridData.DirToBubble, oneGroupGridData.GridInfoCaches);
								this.m_lstGridGroup.Add(item);
							}
						}
					}
				}
			}
			catch (Exception)
			{
			}
		}

		private List<OneGroupGridData> GroupByBubble(List<GridInfoCache> lstParallelGrid, XYZ dirOrder)
		{
			List<OneGroupGridData> list = new List<OneGroupGridData>();
			if (EnumerableExternsion.IsEmpty<GridInfoCache>(lstParallelGrid) || lstParallelGrid.Count == 1)
			{
				return list;
			}
			XYZ driFirstGrid = lstParallelGrid[0].ThisGridLine.Direction;
			List<GridInfoCache> lstSameDirGrid = (from thisItem in lstParallelGrid
			where this.CheckBubbleDir(thisItem, driFirstGrid)
			select thisItem).ToList<GridInfoCache>();
			List<GridInfoCache> lstSameDirGrid2 = (from thisItem in lstParallelGrid
			where this.CheckBubbleDir(thisItem, driFirstGrid * -1.0)
			select thisItem).ToList<GridInfoCache>();
			List<List<GridInfoCache>> list2 = this.GroupAccordingEndSpaceing(lstSameDirGrid, driFirstGrid);
			List<List<GridInfoCache>> list3 = this.GroupAccordingEndSpaceing(lstSameDirGrid2, driFirstGrid * -1.0);
			foreach (List<GridInfoCache> lstGrid in list2)
			{
				List<OneGroupGridData> collection = this.GroupBySpaceing(lstGrid, dirOrder, driFirstGrid);
				list.AddRange(collection);
			}
			foreach (List<GridInfoCache> lstGrid2 in list3)
			{
				List<OneGroupGridData> collection2 = this.GroupBySpaceing(lstGrid2, dirOrder, driFirstGrid * -1.0);
				list.AddRange(collection2);
			}
			return list;
		}

		private List<List<GridInfoCache>> GroupAccordingEndSpaceing(List<GridInfoCache> lstSameDirGrid, XYZ vcDirToBubble)
		{
			List<List<GridInfoCache>> list = new List<List<GridInfoCache>>();
			List<GridInfoCache> list2 = new List<GridInfoCache>();
			for (int i = 0; i < lstSameDirGrid.Count; i++)
			{
				GridInfoCache gridInfoCache = lstSameDirGrid[i];
				if (!list2.Contains(gridInfoCache))
				{
					XYZ endNearBubble = this.GetEndNearBubble(vcDirToBubble, gridInfoCache);
					XYZ xyz = endNearBubble - vcDirToBubble.Normalize() * Common.MMToFeet(500.0);
					XYZ xyz2 = endNearBubble + vcDirToBubble.Normalize() * Common.MMToFeet(500.0);
					XYZ xyz3 = xyz2 - xyz;
					XYZ xyz4 = xyz - xyz2;
					List<GridInfoCache> list3 = new List<GridInfoCache>();
					list3.Add(gridInfoCache);
					for (int j = i + 1; j < lstSameDirGrid.Count; j++)
					{
						GridInfoCache gridInfoCache2 = lstSameDirGrid[j];
						if (!list2.Contains(gridInfoCache2))
						{
							XYZ endNearBubble2 = this.GetEndNearBubble(vcDirToBubble, gridInfoCache2);
							XYZ xyz5 = endNearBubble2 - xyz;
							XYZ xyz6 = endNearBubble2 - xyz2;
							double num = xyz4.AngleTo(xyz6);
							double num2 = xyz3.AngleTo(xyz5);
							if (num <= Math.PI*.5 && num2 <= Math.PI*.5)
							{
								list3.Add(gridInfoCache2);
							}
						}
					}
					list.Add(list3);
					list2.AddRange(list3);
				}
			}
			return list;
		}

		private XYZ GetEndNearBubble(XYZ vcDirToBubble, GridInfoCache gridInfoCache)
		{
			XYZ hyendPoint;
			if (RevitElementExtension.IsSameDirectionTo(gridInfoCache.ThisGridLine.Direction, vcDirToBubble))
			{
				hyendPoint = RevitDocumentExtension.GetEndPoint(gridInfoCache.ThisGridLine, 1);
			}
			else
			{
				hyendPoint = RevitDocumentExtension.GetEndPoint(gridInfoCache.ThisGridLine, 0);
			}
			return hyendPoint;
		}

		private List<OneGroupGridData> GroupBySpaceing(List<GridInfoCache> lstGrid, XYZ dirOrder, XYZ dirToBubble)
		{
			List<OneGroupGridData> list = new List<OneGroupGridData>();
			OneGroupGridData oneGroupGridData = new OneGroupGridData();
			if (EnumerableExternsion.IsEmpty<GridInfoCache>(lstGrid))
			{
				return list;
			}
			oneGroupGridData.DirToBubble = dirToBubble;
			oneGroupGridData.GridInfoCaches.Add(lstGrid[0]);
			for (int i = 1; i < lstGrid.Count; i++)
			{
                if (YJKArchUtils.Utils.Geometry.GreaterThan(this.GetTwoGridDis(lstGrid[i - 1], lstGrid[i], dirOrder), Common.MMToFeet(18000.0)))
				{
					list.Add(oneGroupGridData);
					oneGroupGridData = new OneGroupGridData();
					oneGroupGridData.DirToBubble = dirToBubble;
					oneGroupGridData.GridInfoCaches.Add(lstGrid[i]);
				}
				else
				{
					oneGroupGridData.GridInfoCaches.Add(lstGrid[i]);
				}
				if (i == lstGrid.Count - 1)
				{
					list.Add(oneGroupGridData);
				}
			}
			return list;
		}

		private double GetTwoGridDis(GridInfoCache gridInfoCache1, GridInfoCache gridInfoCache2, XYZ vcDir)
		{
			XYZ origin = gridInfoCache1.ThisGridLine.Origin;
			XYZ origin2 = gridInfoCache2.ThisGridLine.Origin;
			double num = Math.Cos((origin2 - origin).AngleTo(vcDir));
			return origin.DistanceTo(origin2) * num;
		}

		private bool CheckBubbleDir(GridInfoCache gridInfo, XYZ driFirstGrid)
		{
			XYZ xyz = gridInfo.ThisGridLine.Direction;
			if (gridInfo.IsEndBubbleVisible && RevitElementExtension.IsSameDirectionTo(xyz, driFirstGrid))
			{
				return true;
			}
			if (gridInfo.IsStartBubbleVisible)
			{
				xyz *= -1.0;
				if (RevitElementExtension.IsSameDirectionTo(xyz, driFirstGrid))
				{
					return true;
				}
			}
			return false;
		}

		private Dictionary<XYZ, List<GridInfoCache>> OrderParallelGrid(IEnumerable<IGrouping<XYZ, GridInfoCache>> groupDirAndGrid)
		{
			Dictionary<XYZ, List<GridInfoCache>> dictionary = new Dictionary<XYZ, List<GridInfoCache>>();
			foreach (IGrouping<XYZ, GridInfoCache> grouping in groupDirAndGrid)
			{
				XYZ xyz = XYZUtilityMethod.RotateTo(grouping.Key, Math.PI*.5, XYZ.BasisZ);
				List<GridInfoCache> value = grouping.OrderBy((GridInfoCache thisItem) => thisItem, new GridInfoCacheCompare(xyz)).ToList<GridInfoCache>();
				dictionary.Add(xyz, value);
			}
			return dictionary;
		}

		private List<Grid> m_lstAllGrid = new List<Grid>();

		private List<GridGroupDataEx> m_lstParallelGridGroup = new List<GridGroupDataEx>();

		private List<GridGroupDataEx> m_lstGridGroup = new List<GridGroupDataEx>();

		private Document m_doc;

		private Dictionary<int, List<BaseLinkDocumentResultBean>> m_dicLinkInsIdAndGrid = new Dictionary<int, List<BaseLinkDocumentResultBean>>();

		private const double c_dGridDirTol = 500.0;

		private const double c_dParallelMaxSpaceing = 18000.0;

		private const double c_dParallelAngle = 0.0001;
	}
}
